home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / Snippets / Development Tools & Languages / DumpSRec / DumpSRec.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-18  |  19.0 KB  |  701 lines  |  [TEXT/MPS ]

  1.  
  2. /*
  3.  
  4.         DumpSRec -- an MPW Tool
  5.         
  6.         Required files to build:
  7.             DumpSRec.c
  8.             DumpSRec.r
  9.             DumpSRec.rsrc
  10.             DumpSRec.make
  11.         
  12.         Written by Craig Prouse of Apple Developer Technical Support
  13.         Special thanks to C.K. Haun for the original Commando interface!
  14.         Copyright © 1990-91, Apple Computer, Inc. -- ALL RIGHTS RESERVED
  15.         
  16.         This tool converts an arbitrary Macintosh data file or resource into
  17.         Motorola S-Record format, most likely to assist in downloading code
  18.         and data to EPROM programmers or non-Macintosh target platforms.
  19.         
  20.         Command line syntax:
  21.         
  22.         DumpSRec        # write resource or data in S-Record format
  23.         DumpSRec [option…] fileName  > dump ≥ progress
  24.             -a addr                    # dump to hexadecimal target address (default = 0)
  25.             -b count                # include count data bytes per record (default = 32)
  26.             -h                        # suppress S0 header record
  27.             -nh                        # specify new data for the S0 header record
  28.             -rt type[=id]            # dump resource with this type and id (default is data fork)
  29.             -s1                        # generate S1 records, 2-byte addresses (default)
  30.             -s2                        # generate S2 records, 3-byte addresses
  31.             -s3                        # generate S3 records, 4-byte addresses
  32.             -x addr                    # hexadecimal target execution address (default = 0)
  33.  
  34. */
  35.  
  36.         
  37.  
  38. #include <stdio.h>
  39. #include <ctype.h>
  40. #include <string.h>
  41. #include <stdlib.h>
  42. #include <Types.h>
  43. #include <Traps.h>
  44. #include <GestaltEqu.h>
  45. #include <Strings.h>
  46. #include <QuickDraw.h>
  47. #include <Script.h>
  48. #include <Resources.h>
  49. #include <Dialogs.h>
  50. #include <Memory.h>
  51. #include <Files.h>
  52. #include <Folders.h>
  53. #include <Errors.h>
  54. #include <CursorCtl.h>
  55.  
  56.  
  57. #define kSuccess 0
  58. #define kSyntaxErr 1
  59. #define kProcErr 2
  60. #define kSysErr 3
  61. #define kUserAbort -9
  62. #define kBlockSize 16 * sConfig->sLineBytes        /* size of buffer for FSRead */
  63. #define rHdrDLOG 128
  64. #define kHdrText 3
  65. #define kMaxHdrBytes 252
  66. #define kEqualGrayDiv 2
  67. #define kDlogGrayDiv 5
  68. #define chEnter 3
  69. #define chReturn 13
  70. #define chEscape 27
  71. #define sPrefsFileNameC "DumpSRec Prefs"
  72. #define sPrefsFileNameP "\pDumpSRec Prefs"
  73.  
  74. #define topLeft(r) (((Point *) &(r))[0])
  75. #define botRight(r) (((Point *) &(r))[1])
  76. #define    rectHeight(r) ((r).bottom - (r).top)
  77. #define    rectWidth(r) ((r).right - (r).left)
  78.  
  79.  
  80. typedef short Integer;        /* alias integer types to Pascal Toolbox types */
  81. typedef long LongInt;
  82. typedef enum {S0,S1,S2,S3,S7 = 7,S8,S9} TSLine;
  83. typedef struct {
  84.     TSLine sLineType;
  85.     Integer sLineBytes;
  86.     Ptr loadAddress;
  87.     Ptr execAddress;
  88.     char *fileName;
  89.     ResType resourceType;
  90.     Integer resourceID;
  91.     Boolean reqHeader;
  92.     Boolean newHeader;
  93.     } TSParms, *TPSParms;
  94. typedef struct {
  95.     unsigned Integer headerAddress;
  96.     unsigned Integer byteCount;
  97.     unsigned char headerByte[kMaxHdrBytes];
  98.     } TSHdrData, *TPSHdrData, **THSHdrData;
  99.  
  100.  
  101. /* global variables */
  102. char **argList;
  103. LongInt argCount;
  104. char **pShellVariable;
  105. Str255 gPrefsFile;
  106. FSSpec gPrefsSpecStorage, *gPrefsFileSpec = &gPrefsSpecStorage;
  107. Integer gDSRPrefs;
  108. Boolean gHasFSSpecCalls;
  109.  
  110.  
  111. /* Prototypes, in alphabetical order */
  112. Integer AddressSize (TSLine sType);
  113. void BadParmErr (void);
  114. void CenterWindow (WindowPtr theWindow, Rect *theRect, Boolean isDialog);
  115. void ChangeHeader (Handle hRsrc);
  116. void JamAsciiHexByte (Byte oneByte, StringPtr pStr, Integer offset);
  117. void MakeSLine (TSLine sType, Ptr loadAddr, Ptr pData, Integer dataBytes, StringPtr sLine);
  118. pascal Boolean NoDefaultButton (DialogPtr theDialog, EventRecord *theEvent, Integer *itemHit);
  119. Integer ParseCLParms (TSParms *usrCLParms);
  120. Integer SDumpBuffer (Ptr pData, LongInt count, TPSParms sConfig, Boolean termRec);
  121. Integer SDumpData (TPSParms sConfig);
  122. Integer SDumpHeader (TPSParms sConfig);
  123. Integer SDumpResource (TPSParms sConfig);
  124. void SGenErr (void);
  125.  
  126.  
  127.  
  128. int main (int argc, char *argv[], char *envp[]) {
  129.     Integer result = kSuccess;
  130.     TSParms usrCLParms;
  131.     Integer foundVRefNum;
  132.     LongInt foundDirID, response;
  133.     OSErr err;
  134.     
  135.     InitGraf(&qd.thePort);
  136.     InitCursorCtl(nil);
  137.     
  138.     /* Make parameters globally available. */
  139.     argList = argv;
  140.     argCount = argc;
  141.     pShellVariable = envp;
  142.     
  143.     /* Try to open the Prefs file. */
  144.     err = Gestalt(gestaltFSAttr,&response);
  145.     gHasFSSpecCalls = err == noErr && (response & 1 << gestaltHasFSSpecCalls) != 0;
  146.     if (gHasFSSpecCalls) {
  147.         /* use cool new System 7.0 stuff */
  148.         FindFolder(kOnSystemDisk,kPreferencesFolderType,kCreateFolder,&foundVRefNum,&foundDirID);
  149.         FSMakeFSSpec(foundVRefNum,foundDirID,sPrefsFileNameP,gPrefsFileSpec);
  150.         gDSRPrefs = FSpOpenResFile(gPrefsFileSpec,fsRdWrPerm);
  151.         }
  152.     else {
  153.         /* use a gross full pathname built from an MPW Shell variable */
  154.         strcpy(gPrefsFile,getenv("SystemFolder"));
  155.         strcat(gPrefsFile,sPrefsFileNameC);
  156.         gDSRPrefs = openresfile(gPrefsFile);
  157.         }
  158.     
  159.     /* Set default parameters and parse the command line for differences. */
  160.     usrCLParms.sLineType = S1;
  161.     usrCLParms.fileName = nil;
  162.     usrCLParms.resourceType = '\0\0\0\0';
  163.     usrCLParms.resourceID = 0;
  164.     usrCLParms.sLineBytes = 32;
  165.     usrCLParms.loadAddress = 0;
  166.     usrCLParms.execAddress = 0;
  167.     usrCLParms.reqHeader = true;
  168.     usrCLParms.newHeader = false;
  169.     result = ParseCLParms(&usrCLParms);
  170.     
  171.     if (result == kSuccess)
  172.         if (usrCLParms.resourceType == '\0\0\0\0')
  173.             result = SDumpData(&usrCLParms);
  174.         else
  175.             result = SDumpResource(&usrCLParms);
  176.     
  177.     if (result > kSuccess)
  178.         fprintf(stderr,"### %s: Errors prevented normal completion.\n",argList[0]);
  179.     
  180.     /* Close the Prefs file if it's open. */
  181.     if (gDSRPrefs != -1)
  182.         CloseResFile(gDSRPrefs);
  183.         
  184.     return result;
  185.     
  186.     }
  187.  
  188.  
  189.  
  190. Integer ParseCLParms (TSParms *usrCLParms) {
  191.      LongInt i, j, files = 0;
  192.     char *thisArg;
  193.     Integer argLen;
  194.     Boolean hasOperand;
  195.     Integer result = kSuccess;
  196.     
  197.     for (i = 1; i < argCount; i++) {
  198.         if (*argList[i] != '-') {
  199.             /* this argument is a filename */
  200.             argList[++files] = argList[i];                /* collect filenames together */
  201.             }
  202.         else {
  203.             /* this argument is an option */
  204.             argLen = strlen(thisArg = argList[i]);
  205.             for (j = 1; j < argLen; j++)
  206.                 thisArg[j] = tolower(thisArg[j]);        /* convert string to lower case */
  207.             
  208.             /* Implement various changes to default settings. */
  209.             if (!strcmp(thisArg,"-s1"))
  210.                 usrCLParms->sLineType = S1;
  211.             else if (!strcmp(thisArg,"-s2"))
  212.                 usrCLParms->sLineType = S2;
  213.             else if (!strcmp(thisArg,"-s3"))
  214.                 usrCLParms->sLineType = S3;
  215.             else if (!strcmp(thisArg,"-h"))
  216.                 usrCLParms->reqHeader = false;
  217.             else if (!strcmp(thisArg,"-nh"))
  218.                 usrCLParms->newHeader = true;
  219.             else if ((hasOperand = i < argCount - 1) && !strcmp(thisArg,"-rt")) {
  220.                 usrCLParms->resourceType = *(ResType *)strtok(argList[++i],"=");
  221.                 usrCLParms->resourceID = (Integer)atoi(strtok(NULL,""));
  222.                 }
  223.             else if (hasOperand && !strcmp(thisArg,"-a"))
  224.                 usrCLParms->loadAddress = (Ptr)strtol(argList[++i],(char **)NULL,16);
  225.             else if (hasOperand && !strcmp(thisArg,"-x"))
  226.                 usrCLParms->execAddress = (Ptr)strtol(argList[++i],(char **)NULL,16);
  227.             else if (hasOperand && !strcmp(thisArg,"-b"))
  228.                 usrCLParms->sLineBytes = (Integer)atoi(argList[++i]);
  229.             else {
  230.                 /* bad parameter */
  231.                 BadParmErr();
  232.                 if (strstr("-a-b-rt-x",thisArg) == NULL)
  233.                     fprintf(stderr,"Invalid option %s.\n",thisArg);
  234.                 else
  235.                     fprintf(stderr,"Option %s requires an operand.\n",thisArg);
  236.                 result = kSyntaxErr;
  237.                 }
  238.             }
  239.         }
  240.     
  241.     /* Validate a single file and return its path name. */
  242.     if (files == 1)
  243.         usrCLParms->fileName = argList[1];
  244.     else {
  245.         result = kSyntaxErr;
  246.         if (files == 0) {
  247.             BadParmErr();
  248.             fprintf(stderr,"No input file.\n",thisArg);
  249.             }
  250.         else {
  251.             for (i = 2; i <= files; i++) {
  252.                 BadParmErr();
  253.                 fprintf(stderr,"Extra file name: %s.\n",argList[i]);
  254.                 }
  255.             }
  256.         }
  257.     return result;
  258.     
  259.     }
  260.  
  261.  
  262.  
  263. Integer SDumpHeader (TPSParms sConfig) {
  264.     Handle hRsrc;
  265.     TPSHdrData pHdr;
  266.     Integer result = kSuccess;
  267.     Str255 theS0Line;
  268.     
  269.     hRsrc = Get1Resource('SHDR',0);
  270.     if (hRsrc == nil) {
  271.         SGenErr();
  272.         fprintf(stderr,"Error loading default header resource 'SHDR' (ID=0) from %s.\n",argList[0]);
  273.         result = kProcErr;
  274.         }
  275.     else {
  276.         if (sConfig->newHeader)
  277.             ChangeHeader(hRsrc);
  278.         MoveHHi(hRsrc);
  279.         HLock(hRsrc);
  280.         pHdr = *(THSHdrData)hRsrc;
  281.         MakeSLine(S0,(Ptr)pHdr->headerAddress,pHdr->headerByte,pHdr->byteCount,theS0Line);
  282.         fprintf(stdout,"%s\n",theS0Line);
  283.         HUnlock(hRsrc);
  284.         }
  285.     return result;
  286.     }
  287.     
  288.     
  289.  
  290. Integer SDumpResource (TPSParms sConfig) {
  291.     Handle hRsrc;
  292.     ResType rType;
  293.     char *rFile;
  294.     LongInt dataSize;
  295.     Integer id, fileRefNum;
  296.     Integer result = kSuccess;
  297.  
  298.     fileRefNum = openrfperm(rFile = sConfig->fileName,0,fsRdPerm);
  299.     if (fileRefNum == -1)
  300.         result = kProcErr;        /* will print diagnostics later */
  301.     else {
  302.         hRsrc = Get1Resource(rType = sConfig->resourceType,id = sConfig->resourceID);
  303.         if (hRsrc == nil) {
  304.             CloseResFile(fileRefNum);
  305.             result = kProcErr;        /* will print diagnostics later */
  306.             }
  307.         else {
  308.             dataSize = SizeResource(hRsrc);
  309.             DetachResource(hRsrc);
  310.             CloseResFile(fileRefNum);
  311.             MoveHHi(hRsrc);
  312.             HLock(hRsrc);
  313.                     
  314.             if (sConfig->reqHeader)
  315.                 result = SDumpHeader(sConfig);
  316.         
  317.             if (result == kSuccess)
  318.                 result = SDumpBuffer(*hRsrc,dataSize,sConfig,true);
  319.             
  320.             HUnlock(hRsrc);
  321.             DisposHandle(hRsrc);
  322.             }
  323.         }
  324.     
  325.     if (result != kSuccess) {
  326.         if (fileRefNum == -1) {
  327.             SGenErr();
  328.             fprintf(stderr,"Could not open resource file %s.\n",rFile);
  329.             }
  330.         else if (hRsrc == nil) {
  331.             SGenErr();
  332.             fprintf(stderr,"Could not load resource '%.4s' (ID=%d).\n",&rType,id);
  333.             }
  334.         }
  335.     return result;
  336.  
  337.     }
  338.  
  339.  
  340.  
  341. Integer SDumpData (TPSParms sConfig) {
  342.     Handle dataBuf;
  343.     char *dFile;
  344.     Integer fileRefNum, fErr = noErr, dumpErr = kSuccess;
  345.     LongInt byteCount, totalBytes = 0;
  346.     Boolean eof;
  347.     Integer result = kSuccess;
  348.  
  349.     dataBuf = NewHandle(kBlockSize);
  350.     if (dataBuf == nil) {
  351.         SGenErr();
  352.         fprintf(stderr,"Memory allocation failure.\n");
  353.         result = kSysErr;
  354.         }
  355.     else {
  356.         MoveHHi(dataBuf);
  357.         HLock(dataBuf);
  358.         fErr = fsopen(dFile = sConfig->fileName,0,&fileRefNum);
  359.         if (fErr != noErr) {
  360.             SGenErr();
  361.             fprintf(stderr,"Could not open data file %s.\n",dFile);
  362.             result = kProcErr;
  363.             }
  364.         else {
  365.             byteCount = 1;
  366.             if (fErr = FSRead(fileRefNum,&byteCount,*dataBuf) != eofErr) {
  367.                 /* Make sure there's some data before outputting the header. */
  368.                 SetFPos(fileRefNum,fsFromStart,0);
  369.                 if (sConfig->reqHeader)
  370.                     result = SDumpHeader(sConfig);
  371.                 }
  372.             
  373.             if (result == kSuccess)
  374.                 do {
  375.                     byteCount = kBlockSize;
  376.                     fErr = FSRead(fileRefNum,&byteCount,*dataBuf);
  377.                     eof = fErr == eofErr;
  378.                     if (fErr == noErr || eof) {
  379.                         dumpErr = SDumpBuffer(*dataBuf,byteCount,sConfig,eof && totalBytes > 0);
  380.                         sConfig->loadAddress += byteCount;
  381.                         totalBytes += byteCount;
  382.                         }
  383.                     } while (dumpErr == kSuccess && fErr == noErr);
  384.             
  385.             /* handle error conditions which may have resulted */
  386.             if (dumpErr != kSuccess)
  387.                 result = dumpErr;        /* diagnostics printed in SDumpBuffer */
  388.             else {
  389.                 if (fErr != eofErr) {
  390.                     SGenErr();
  391.                     fprintf(stderr,"Error reading data file %s.\n",dFile);
  392.                     result = kProcErr;
  393.                     }
  394.                 else
  395.                     if (totalBytes == 0) {
  396.                         SGenErr();
  397.                         fprintf(stderr,"Input file %s has an empty data fork.\n",dFile);
  398.                         result = kProcErr;
  399.                         }
  400.                 }
  401.             FSClose(fileRefNum);
  402.             }
  403.         DisposHandle(dataBuf);
  404.         }
  405.     return result;
  406.  
  407.     }
  408.  
  409.  
  410.  
  411. /* SDumpBuffer may cause memory to move, as it allocates a handle! */
  412. Integer SDumpBuffer (Ptr pData, LongInt count, TPSParms sConfig, Boolean termRec) {
  413.     Handle lineBuffer;
  414.     Ptr thisLoadAddress;
  415.     Integer addrBytes, reqLineBytes, maxBytes, thisLineBytes;
  416.     TSLine sType;
  417.     
  418.     sType = sConfig->sLineType;
  419.     addrBytes = AddressSize(sType);
  420.     
  421.     /* Allocate a buffer for building S-Lines. */
  422.     reqLineBytes = sConfig->sLineBytes;
  423.     if (reqLineBytes > (maxBytes = 254 - addrBytes)) {
  424.         SGenErr();
  425.         fprintf(stderr,"S%d record maximum data bytes = %d.\n",sType,maxBytes);
  426.         return kProcErr;
  427.         }
  428.     lineBuffer = NewHandle(7 + 2 * (addrBytes + reqLineBytes));
  429.     if (lineBuffer == nil) {
  430.         SGenErr();
  431.         fprintf(stderr,"Memory allocation failure.\n");
  432.         return kSysErr;
  433.         }
  434.     MoveHHi(lineBuffer);
  435.     HLock(lineBuffer);        /* Writing to standard output may move memory as well! */
  436.     
  437.     thisLoadAddress = sConfig->loadAddress;
  438.     /* Build S-Lines for all the data in turn. */
  439.     while (count > 0) {
  440.         thisLineBytes = (count < reqLineBytes) ? count : reqLineBytes;
  441.         MakeSLine(sType,thisLoadAddress,pData,thisLineBytes,*lineBuffer);
  442.         fprintf(stdout,"%s\n",*lineBuffer);
  443.         pData += thisLineBytes;
  444.         count -= thisLineBytes;
  445.         thisLoadAddress += thisLineBytes;
  446.         }
  447.     
  448.     /* Build a termination record appropriate to type of S-Record block. */
  449.     if (termRec) {
  450.         MakeSLine(10 - sType,sConfig->execAddress,nil,0,*lineBuffer);
  451.         fprintf(stdout,"%s\n",*lineBuffer);
  452.         }
  453.     
  454.     DisposHandle(lineBuffer);
  455.     return kSuccess;
  456.     
  457.     }
  458.  
  459.  
  460.  
  461. void MakeSLine (TSLine sType, Ptr loadAddr, Ptr pData, Integer dataBytes, StringPtr sLine) {
  462.     Integer i, offset, addrBytes;
  463.     LongInt checksum;
  464.     
  465.     SpinCursor(1);
  466.     addrBytes = AddressSize(sType);
  467.     
  468.     /* Begin the S-Line with 'S' after first storing sType in the second byte. */
  469.     JamAsciiHexByte( (Byte)sType,sLine,0);
  470.     sLine[0] = 'S';
  471.     
  472.     /* Initialize checksum with record length and add record length to the S-Line. */
  473.     checksum = addrBytes + dataBytes + 1;
  474.     JamAsciiHexByte( (Byte)checksum,sLine,2);
  475.     
  476.     /* Checksum and store the load address. */
  477.     for (i = 0, offset = 2 + 2 * addrBytes; i < addrBytes; i++, offset -= 2) {
  478.         checksum += (Byte)loadAddr;
  479.         JamAsciiHexByte( (Byte)loadAddr,sLine,offset);
  480.         (LongInt)loadAddr >>= 8;
  481.         }
  482.     
  483.     /* Checksum and store the data bytes. */
  484.     for (i = 0, offset = 4 + 2 * addrBytes; i < dataBytes; i++, offset += 2) {
  485.         checksum += *pData;
  486.         JamAsciiHexByte(*pData,sLine,offset);
  487.         pData++;
  488.         }
  489.     
  490.     /* Invert all the checksum bits and store the low byte for transmission. */
  491.     checksum = ~checksum;
  492.     JamAsciiHexByte( (Byte)checksum,sLine,4 + 2 * (addrBytes + dataBytes) );
  493.     
  494.     /* Housekeeping--Terminate with NULL. */
  495.     sLine[6 + 2 * (addrBytes + dataBytes)] = '\0';
  496.     
  497.     }
  498.  
  499.  
  500.  
  501. void JamAsciiHexByte (Byte oneByte, StringPtr pStr, Integer offset) {
  502.     static unsigned char hexDigit[] = "0123456789ABCDEF";
  503.  
  504.     /*    Convert a byte to its ASCII hexadecimal representation.    */
  505.     /*    Jam it into a string (*strBuffer) at offset strPos.        */
  506.     pStr[offset] = hexDigit[oneByte >> 4];
  507.     pStr[offset+1] = hexDigit[oneByte & 0x0F];
  508.     
  509.     }
  510.  
  511.  
  512.  
  513. Integer AddressSize (TSLine sType) {
  514.     Integer addrBytes;
  515.     
  516.     /* Address field size depends on sType. */
  517.     switch (sType) {
  518.         case S0: case S1: case S9:
  519.             addrBytes = 2;
  520.             break;
  521.         case S2: case S8:
  522.             addrBytes = 3;
  523.             break;
  524.         case S3: case S7:
  525.             addrBytes = 4;
  526.             break;
  527.         }
  528.     return addrBytes;
  529.     
  530.     }
  531.  
  532.  
  533.  
  534. void BadParmErr (void) {
  535.  
  536.     fprintf(stderr,"### %s: Syntax: ",argList[0]);
  537.     fprintf(stderr,"DumpSRec [-a addr] [-b count] [-h | -nh] [-rt type[=id]] ");
  538.     fprintf(stderr,"[-s1 | -s2 | -s3] [-x addr] fileName [> dump] [≥ progress]\n");
  539.     fprintf(stderr,"### %s: Bad parameter: ",argList[0]);
  540.     
  541.     }
  542.  
  543.  
  544.  
  545. void SGenErr (void) {
  546.     
  547.     fprintf(stderr,"### %s: Error in S-Record generation: ",argList[0]);
  548.     
  549.     }
  550.  
  551.  
  552.  
  553. void ChangeHeader (Handle hRsrc) {
  554.     DialogPtr pAskHdr;
  555.     Integer itemHit;
  556.     Integer itemType;
  557.     Handle item;
  558.     Rect box;
  559.     Str255 header;
  560.     Handle newRsrc;
  561.     
  562.     pAskHdr = GetNewDialog(rHdrDLOG,nil,(WindowPtr)-1);
  563.     CenterWindow((WindowPtr)pAskHdr,&qd.screenBits.bounds,true);
  564.     ShowWindow((WindowPtr)pAskHdr);
  565.     Show_Cursor(ARROW_CURSOR);
  566.     do {
  567.         ModalDialog(NoDefaultButton,&itemHit);
  568.         } while (itemHit != ok && itemHit != cancel);
  569.     GetDItem(pAskHdr,kHdrText,&itemType,&item,&box);
  570.     GetIText(item,&header);
  571.     DisposDialog(pAskHdr);
  572.     if (itemHit == ok) {
  573.         (**(THSHdrData)hRsrc).headerAddress = 0;
  574.         p2cstr(header);
  575.         (**(THSHdrData)hRsrc).byteCount = strlen(header);
  576.         strncpy((**(THSHdrData)hRsrc).headerByte,header,kMaxHdrBytes - 1);
  577.         
  578.         if (gDSRPrefs == -1) {
  579.             if (gHasFSSpecCalls)
  580.                 FSpCreateResFile(gPrefsFileSpec,'','',nil);
  581.             else
  582.                 createresfile(gPrefsFile);
  583.             if (ResError() != noErr)
  584.                 fprintf(stderr,"### %s: Error creating preferences file.\n",argList[0]);
  585.             else {
  586.                 if (gHasFSSpecCalls)
  587.                     gDSRPrefs = FSpOpenResFile(gPrefsFileSpec,fsRdWrPerm);
  588.                 else
  589.                     gDSRPrefs = openresfile(gPrefsFile);
  590.                 newRsrc = hRsrc;
  591.                 HandToHand(&newRsrc);
  592.                 addresource(newRsrc,'SHDR',0,"");
  593.                 WriteResource(newRsrc);
  594.                 DisposHandle(newRsrc);
  595.                 }
  596.             }
  597.         else {
  598.             ChangedResource(hRsrc);
  599.             if (ResError() != noErr)
  600.                 fprintf(stderr,"### %s: Cannot modify default header.\n",argList[0]);
  601.             }
  602.         }
  603.     
  604.     }
  605.  
  606.  
  607.  
  608. void CenterWindow (WindowPtr theWindow, Rect *theRect, Boolean isDialog)
  609. {
  610.     Point    offscreenPt, portRef;
  611.     Rect    portRect, strucRect, ctrRect = *theRect;
  612.     short    portH, portV, windH, windV;
  613.     short    grayDiv, x, y;
  614.     Boolean    originalState;
  615.  
  616.     SetPort(theWindow);
  617.     originalState = ((WindowPeek) theWindow)->visible;
  618.     
  619.     // According to the Human Interface Notes, dialogs are nominally
  620.     // centered evenly left and right, with gray space divided 20%
  621.     // above and 80% below (1/5 above and 4/5 below) the window.
  622.     
  623.     if (isDialog)
  624.         grayDiv = kDlogGrayDiv;
  625.     else
  626.         grayDiv = kEqualGrayDiv;        // or we can actually center it
  627.     
  628.     // The window is temporarily moved beyond the lower right corner of
  629.     // the desktop region. The dimensions of the window's portRect form
  630.     // a basis for additional margin to guarantee that no part of the
  631.     // window's frame will appear (even momentarily) in the lower right
  632.     // corner of the desktop.
  633.     
  634.     offscreenPt = botRight((**GetGrayRgn()).rgnBBox);
  635.     portRect = theWindow->portRect;
  636.     offscreenPt.h += rectWidth(portRect);
  637.     offscreenPt.v += rectHeight(portRect);
  638.     MoveWindow(theWindow, offscreenPt.h, offscreenPt.v, false);        // move it offscreen
  639.     ShowHide(theWindow, true);
  640.     
  641.     // can only get structure data after window is "drawn"
  642.     
  643.     strucRect = (**((WindowPeek) theWindow)->strucRgn).rgnBBox;
  644.     ShowHide(theWindow, originalState);                                // leave it the way it was
  645.     if (EqualRect(theRect, &qd.screenBits.bounds))
  646.         ctrRect.top += GetMBarHeight();
  647.     portH = rectWidth(ctrRect);
  648.     portV = rectHeight(ctrRect);
  649.     windH = rectWidth(strucRect);
  650.     windV = rectHeight(strucRect);
  651.     portRef = topLeft(portRect);
  652.     LocalToGlobal(&portRef);
  653.     
  654.     // Note that while the intent is to center the window structure,
  655.     // MoveWindow sets the location of the window content, so it is
  656.     // necessary to add the top and left frame thicknesses to the
  657.     // arguments of MoveWindow.
  658.     
  659.     x = ctrRect.left + (portH - windH) / kEqualGrayDiv + (portRef.h - strucRect.left);
  660.     y = ctrRect.top + (portV - windV) / grayDiv + (portRef.v - strucRect.top);
  661.     MoveWindow(theWindow, x, y, false);                                // finally it's centered!
  662. }
  663.  
  664.  
  665.  
  666. pascal Boolean NoDefaultButton (DialogPtr theDialog, EventRecord *theEvent, Integer *itemHit) {
  667.     Boolean cmdKeyPressed, result = false;
  668.     Integer charCode;
  669.     Integer itemType;
  670.     Handle item;
  671.     Rect box;
  672.     LongInt finalTicks;
  673.     
  674.     /* This is a filter proc for a modal dialog which needs to use the return key for   */
  675.     /* something other than a default button, for instance a dialog with a relatively   */
  676.     /* large TextEdit field. For those that like using the keyboard to dismiss dialogs, */
  677.     /* it supports Cmd-Return and Enter as equivalents to the OK button and Escape as   */
  678.     /* an equivalent to the Cancel button. */
  679.     if (theEvent->what == keyDown) {
  680.         charCode = theEvent->message & 0xFF;
  681.         cmdKeyPressed = (theEvent->modifiers & cmdKey) != 0;
  682.         if (charCode == chEnter || charCode == chReturn && cmdKeyPressed) {
  683.             result = true;
  684.             *itemHit = ok;
  685.             }
  686.         else if (charCode == chEscape) {
  687.             result = true;
  688.             *itemHit = cancel;
  689.             }
  690.         if (result) {
  691.             GetDItem(theDialog,*itemHit,&itemType,&item,&box);
  692.             HiliteControl((ControlHandle)item,inButton);
  693.             Delay(8,&finalTicks);
  694.             HiliteControl((ControlHandle)item,0);
  695.             }
  696.         }
  697.     
  698.     return result;
  699.     
  700.     }
  701.